#region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

using Osh;

namespace OshHost
{
	public class OshCommandParser : IDisposable
	{
		#region CommandParserWindow Class
		private class CommandParserWindow : Control
		{
			private OshCommandParser _parser;
			private const int WM_APP_PROCESS_COMMAND = Win32.WM_APP + 1;
			private bool _started;

			public CommandParserWindow(OshCommandParser parser, string name) : base(name)
			{
				_parser = parser;
				this.Visible = false;
				this.CreateHandle();
				_started = true;
			}

			protected override CreateParams CreateParams
			{
				get
				{
					CreateParams parameters = base.CreateParams;
					parameters.Style &= ~(int)Win32.WindowStyles.WS_CHILD;
					return parameters;
				}
			}

			protected override void WndProc(ref Message m)
			{
				if(!_started)
				{
					base.WndProc(ref m);
					return;
				}

				if(m.Msg == Win32.WM_SETTEXT)
					OnSetText(ref m);
				else if(m.Msg == WM_APP_PROCESS_COMMAND)
					OnProcessCommand(ref m);
				else
					base.WndProc(ref m);
			}

			private void OnSetText(ref Message m)
			{
				if(m.LParam == IntPtr.Zero)
					return;

				string command = Marshal.PtrToStringUni(m.LParam);
				if(string.IsNullOrEmpty(command))
					return;

				IntPtr commandPtr = Marshal.StringToBSTR(command);
				if(Win32.PostMessage(new HandleRef(this, this.Handle), WM_APP_PROCESS_COMMAND, IntPtr.Zero, commandPtr) == 0)
				{
					// In case of a error delete the allocated string.
					Marshal.FreeBSTR(commandPtr);
					return;
				}
			}

			private void OnProcessCommand(ref Message m)
			{
				if(m.LParam == IntPtr.Zero)
					return;

				try
				{
					string command = Marshal.PtrToStringBSTR(m.LParam);
					if(string.IsNullOrEmpty(command))
						return;

					_parser.OnCommand(command);
				}
				finally
				{
					Marshal.FreeBSTR(m.LParam);
				}
			}

		}
		#endregion CommandParserWindow Class

		private CommandParserWindow _window;

		public OshCommandParser()
		{
			_window = new CommandParserWindow(this, "OSH_CmdParser");
		}

		private void OnCommand(string command)
		{
			if(this.Command != null)
				this.Command(this, new OshCommandEventArgs(command));
		}

		public event EventHandler<OshCommandEventArgs> Command;


		#region IDisposable Members
		~OshCommandParser()
		{
			Dispose(false);
		}

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		private bool _disposed = false;
		protected void Dispose(bool disposing)
		{
			if(!_disposed)
				return;

			_disposed = true;
			if(disposing)
			{
				// Dispose managed resources.
				_window.Dispose();
			}
		}
		#endregion
	}
}
